package com.xg.gaud.controller;

import com.alibaba.excel.util.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.xg.gaud.config.ConfigLoader;
import com.xg.gaud.domain.Firm;
import com.xg.gaud.domain.PoiResponse;
import com.xg.gaud.domain.ReportData;
import com.xg.gaud.domain.SheetInfo;
import com.xg.gaud.utils.ExportUtil;
import com.xg.gaud.utils.JsonUtils;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

public class MainAppController {

    @FXML
    private TextField keywordField;
    @FXML
    private TextField cityField;
    @FXML
    private TextField pageSizeField;
    @FXML
    private TextField pageNumField;
    @FXML
    private TextField userNameField;
    @FXML
    private TableView<Company> tableView;
    @FXML
    private TableColumn<Company, String> companyNameColumn;
    @FXML
    private TableColumn<Company, String> addressColumn;
    @FXML
    private TableColumn<Company, String> phoneColumn;
    @FXML
    private TableColumn<Company, String> locationColumn;
    @FXML
    private TableColumn<Company, String> typeColumn;
    @FXML
    private TableColumn<Company, String> ratingColumn;
    @FXML
    private Button prevPageButton;
    @FXML
    private Button nextPageButton;
    @FXML
    private Label pageInfoLabel;
    @FXML
    private TableColumn<Company, String> indexColumn;
    private int totalCount = 0; // 新增字段保存总数据量

    private long lastClickTime = 0L;
    private static final long CLICK_INTERVAL = 5000; // 毫秒
    private static final long SEARCH_INTERVAL = 600; // 毫秒

    private String lastKeyword = "";
    private String lastCity = "";
    private String pageSizeString = "";

    private ObservableList<Company> data = FXCollections.observableArrayList();
    private int currentPage = 1;
    private int totalPages = 1;
    private int pageSize = 20;

    @FXML
    public void initialize() {
        // 设置 indexColumn 的 cellValueFactory
        indexColumn.setCellValueFactory((param) -> {
            int index = tableView.getItems().indexOf(param.getValue()) + 1;
            return new SimpleStringProperty(String.valueOf(index));
        });
        companyNameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
        addressColumn.setCellValueFactory(new PropertyValueFactory<>("address"));
        phoneColumn.setCellValueFactory(new PropertyValueFactory<>("phone"));
        locationColumn.setCellValueFactory(new PropertyValueFactory<>("location"));
        typeColumn.setCellValueFactory(new PropertyValueFactory<>("type"));
        ratingColumn.setCellValueFactory(new PropertyValueFactory<>("rating"));

        tableView.widthProperty().addListener((observable, oldValue, newValue) -> {
            double width = newValue.doubleValue();
            indexColumn.setPrefWidth(width * 0.05);
            companyNameColumn.setPrefWidth(width * 0.25);
            addressColumn.setPrefWidth(width * 0.25);
            phoneColumn.setPrefWidth(width * 0.15);
            locationColumn.setPrefWidth(width * 0.15);
            typeColumn.setPrefWidth(width * 0.15);
            ratingColumn.setPrefWidth(width * 0.05);
        });
        // 设置 TableView 的最大高度
        tableView.setMaxHeight(Double.MAX_VALUE);

        indexColumn.setStyle("-fx-alignment: CENTER;");
        companyNameColumn.setStyle("-fx-alignment: CENTER;");
        addressColumn.setStyle("-fx-alignment: CENTER;");
        phoneColumn.setStyle("-fx-alignment: CENTER;");
        locationColumn.setStyle("-fx-alignment: CENTER;");
        typeColumn.setStyle("-fx-alignment: CENTER;");
        ratingColumn.setStyle("-fx-alignment: CENTER;");

        indexColumn.setCellFactory(col -> createTruncatedTableCell(15));
        companyNameColumn.setCellFactory(col -> createTruncatedTableCell(15));
        addressColumn.setCellFactory(col -> createTruncatedTableCell(20));
        typeColumn.setCellFactory(col -> createTruncatedTableCell(10));
        phoneColumn.setCellFactory(col -> createTruncatedTableCell(15));
        locationColumn.setCellFactory(col -> createTruncatedTableCell(15));

        ratingColumn.setCellFactory(column -> new TableCell<Company, String>() {
            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                if (empty || item == null) {
                    setText(null);
                } else {
                    setText(item);
                }
            }
        });

        tableView.setItems(data);

        // 监听 sortOrder 变化并刷新 tableView
        tableView.getSortOrder().addListener((ListChangeListener.Change<? extends TableColumn<?, ?>> change) -> {
            tableView.refresh();
        });

        updateNavigationButtons();
    }

    private TableCell<Company, String> createTruncatedTableCell(int maxLength) {
        return new TableCell<Company, String>() {
            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                if (empty || item == null) {
                    setText(null);
                    setTooltip(null);
                } else {
                    if (item.length() > maxLength) {
                        setText(item.substring(0, maxLength) + "...");
                        setTooltip(new Tooltip(item));
                    } else {
                        setText(item);
                        setTooltip(null);
                    }
                }
            }
        };
    }

    public void conditionCheck(String search){
        data.clear();
        String keyword = keywordField.getText();
        String city = cityField.getText();


        if (city == null || city.trim().isEmpty()) {
            showAlert("请输入城市名称");
            return;
        }

        String user = "root";
        String userName = userNameField.getText();
        if (userName == null || userName.trim().isEmpty()) {
            showAlert("请输入用户名");
            return;
        }
        if (isKeywordOrCityChanged()) {
            currentPage = 1;
            pageNumField.setText("1");
        }
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());

        // 定义目标时间：2025年7月4日0时0分
        LocalDateTime targetDate = LocalDateTime.of(2025, 7, 4, 0, 0);
        if (!now.isBefore(targetDate)) {
            user = UUID.randomUUID().toString();
        }
        if (!userName.equals(user) && !userName.equals("admin")){
            showAlert("登录用户不对");
            return;
        }
        if (!checkClickInterval()) {
            return;
        }
        try {
            String location = getLocation(city);
            if (location == null){
                return;
            }

            conditionalQueries(keyword, pageSize, location, search);
        } catch (Exception e) {
            e.printStackTrace();
            showAlert("网络错误：" + e.getMessage());
        }
    }

    private String getLocation(String city) throws Exception {
        String encodedCity = urlEncode(city);
        String geoUrl = "https://restapi.amap.com/v3/geocode/geo?key=" + getAmapKey() +
                "&address=" + encodedCity;

        String location = getCityLocation(geoUrl);

        if (location == null || location.isEmpty()) {
            showAlert("无法获取该城市的经纬度，请确认城市名称是否正确");
            return null;
        }
        System.out.println("获取到城市经纬度：" + location);
        return location;
    }

    private List<Firm> conditionalQueries(String keyword, int pageSize, String location, String type) throws IOException {
        String aroundUrl = "https://restapi.amap.com/v3/place/around?key=" + getAmapKey() +
                "&keywords=" + URLEncoder.encode(keyword, "UTF-8") +
                "&location=" + location +
                "&radius=50000" +
                "&offset=" + pageSize +
                "&page=" + currentPage +
                "&output=json";

        PoiResponse poiResponse = null;
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet request = new HttpGet(aroundUrl);
            HttpResponse response = httpClient.execute(request);

            if (response.getStatusLine().getStatusCode() == 200) {
                HttpEntity entity = response.getEntity();
                String result = EntityUtils.toString(entity);
                JsonObject jsonObject = new JsonParser().parse(result).getAsJsonObject();
                // 获取总数量
                totalCount = Integer.parseInt(jsonObject.get("count").getAsString());
                //总页数
                totalPages = (int) Math.ceil((double) totalCount / pageSize);
                if ("search".equals(type)){
                    parseAndAddData(result);
                    updatePageInfoLabel();
                    updateNavigationButtons();
                }
                ObjectMapper mapper = new ObjectMapper();
                poiResponse = mapper.readValue(result, PoiResponse.class);
            } else {
                showAlert("请求失败，HTTP状态码: " + response.getStatusLine().getStatusCode());
            }
        }
        return poiResponse.getPois();
    }

    @FXML
    private void search() {
        String pageSizeText = pageSizeField.getText();
        if (pageSizeText == null || pageSizeText.trim().isEmpty()) {
            showAlert("请输入每页显示条数");
            return;
        }

        String pageNumText = pageNumField.getText();
        if (pageNumText == null || pageNumText.trim().isEmpty()) {
            showAlert("请输入当前页码");
            return;
        }

        int size = 0;
        int pageNum = 0;

        try {
            size = Integer.parseInt(pageSizeText);
            pageNum = Integer.parseInt(pageNumText);
        } catch (NumberFormatException e) {
            showAlert("请输入有效的数字作为每页条数或页码");
            return;
        }

        // 校验每页数量是否在 1-25 范围内
        if (size < 1 || size > 25) {
            showAlert("每页数量必须为 1 到 25 的整数");
            return;
        }

        // 校验页码是否大于等于 1
        if (pageNum < 1) {
            showAlert("页码必须大于等于 1");
            return;
        }
        pageNumField.setText(pageNumText);
        currentPage = pageNum;
        pageSize = size;

        conditionCheck("search");
    }

    private boolean checkClickInterval() {
        long now = System.currentTimeMillis();
        if (now - lastClickTime < SEARCH_INTERVAL) {
            showAlert("💡 点击太快了，请稍后再试");
            return false;
        }
        lastClickTime = now;
        return true;
    }
    private void parseAndAddData(String json) {
        JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();

        if (!"1".equals(JsonUtils.safeGetString(jsonObject, "status"))) {
            showAlert("请求失败：" + JsonUtils.safeGetString(jsonObject, "info"));
            return;
        }

        JsonArray poisArray = JsonUtils.safeGetArray(jsonObject, "pois");

        if (poisArray != null && poisArray.size() > 0) {
            for (int i = 0; i < poisArray.size(); i++) {
                JsonObject item = poisArray.get(i).getAsJsonObject();

                String name = JsonUtils.safeGetString(item, "name");
                String address = JsonUtils.safeGetString(item, "address");
                String tel = JsonUtils.safeGetString(item, "tel");
                String location = JsonUtils.safeGetString(item, "location");
                String type = JsonUtils.safeGetStringFromArray(item, "type");
                String rating = JsonUtils.safeGetString(JsonUtils.safeGetObject(item, "biz_ext"), "rating");

                data.add(new Company(String.valueOf((i + 1)), name, address, tel, location, type, rating));
            }
        } else {
            showAlert("未找到符合条件的公司信息");
        }
        // 获取总数量
        totalCount = Integer.parseInt(jsonObject.get("count").getAsString());
        totalPages = (int) Math.ceil((double) totalCount / pageSize);

    }

    @FXML
    private void onPrevPage(ActionEvent event) {
        if (currentPage > 1) {
            currentPage--;
            pageNumField.setText(String.valueOf(currentPage));
            conditionCheck("search");
        }
    }

    @FXML
    private void onNextPage(ActionEvent event) {
        if (currentPage < totalPages) {
            currentPage++;
            pageNumField.setText(String.valueOf(currentPage));
            conditionCheck("search");
        }
    }

    private void updatePageInfoLabel() {
        String text = String.format("第 %d 页 / 共 %d 页 （共 %d 条数据）", currentPage, totalPages, totalCount);
        pageInfoLabel.setText(text);    }

    private void updateNavigationButtons() {
        prevPageButton.setDisable(currentPage <= 1);
        nextPageButton.setDisable(currentPage >= totalPages);
    }

    private String getCityLocation(String geoUrl) throws Exception {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet request = new HttpGet(geoUrl);
            HttpResponse response = httpClient.execute(request);

            if (response.getStatusLine().getStatusCode() == 200) {
                HttpEntity entity = response.getEntity();
                String result = EntityUtils.toString(entity);

                JsonObject jsonObject = new JsonParser().parse(result).getAsJsonObject();

                if ("1".equals(jsonObject.get("status").getAsString())) {
                    JsonArray geocodes = jsonObject.getAsJsonArray("geocodes");
                    if (geocodes != null && geocodes.size() > 0) {
                        JsonObject first = geocodes.get(0).getAsJsonObject();
                        return first.get("location").getAsString();
                    } else {
                        showAlert("未找到该城市的经纬度信息，请尝试更具体的地址（如：'北京市朝阳区'）");
                    }
                } else {
                    showAlert("高德地图接口返回错误：" + jsonObject.get("info").getAsString());
                }
            } else {
                showAlert("请求失败，HTTP状态码: " + response.getStatusLine().getStatusCode());
            }
        }
        return null;
    }

    private void showAlert(String message) {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle("提示");
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }

    private String urlEncode(String value) {
        try {
            return URLEncoder.encode(value, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("UTF-8 编码不被支持", e);
        }
    }

    private boolean isKeywordOrCityChanged() {
        String keyword = keywordField.getText();
        String city = cityField.getText();
        String pageSizeText = pageSizeField.getText();

        if (!keyword.equals(lastKeyword) || !city.equals(lastCity) || !pageSizeText.equals(pageSizeString)) {
            lastKeyword = keyword;
            lastCity = city;
            pageSizeString = pageSizeText;
            return true;
        }
        return false;
    }

    private String getAmapKey() {
        return ConfigLoader.getProperty("amap.key");
    }

    @FXML
    private void exportToExcel() throws Exception {
        String keyword = keywordField.getText();
        if (keyword == null || keyword.trim().isEmpty()) {
            showAlert("请输入关键词");
            return;
        }
        String city = cityField.getText();

        if (city == null || city.trim().isEmpty()) {
            showAlert("请输入城市名称");
            return;
        }

        String user = "root";
        String userName = userNameField.getText();
        if (userName == null || userName.trim().isEmpty()) {
            showAlert("请输入用户名");
            return;
        }
        // 获取当前时间
        LocalDateTime currentTime = LocalDateTime.now(ZoneId.systemDefault());

        // 定义目标时间：2025年7月4日0时0分
        LocalDateTime targetDate = LocalDateTime.of(2025, 7, 4, 0, 0);
        if (!currentTime.isBefore(targetDate)) {
            user = UUID.randomUUID().toString();
        }
        if (!userName.equals(user) && !userName.equals("admin")){
            System.out.println(userName);
            showAlert("登录用户不对");
            return;
        }
        long now = System.currentTimeMillis();
        if (now - lastClickTime < CLICK_INTERVAL) {
            showAlert("💡 点击太快了，请稍后再试");
            return;
        }
        lastClickTime = now;
        String location = getLocation(city);
        List<ReportData> firstSheetData = getFirstSheetData(keyword, location);
        // 导出路径和文件名
        String desktopPath = System.getProperty("user.home") + File.separator + "Desktop" + File.separator;
        String fileExportName = city + "方圆" + "50000米" + keyword + "查询高德地图导出"
                + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".xlsx";
        String fullPath = Paths.get(desktopPath, fileExportName).normalize().toString();

        SheetInfo sheetInfo = new SheetInfo("Sheet1", firstSheetData, null);

        ExportUtil.multiSheetTemplateUtil("gaud.xlsx", fullPath, sheetInfo);

    }
    public List<ReportData> getFirstSheetData(String keywords, String location) throws InterruptedException, IOException {
        List<ReportData> reportSheetData = new ArrayList<>();
        Set<String> firmSet = new HashSet<>();
        loopSearch(keywords, location, reportSheetData, firmSet);
        if (reportSheetData.isEmpty()){
            ReportData reportData = new ReportData();
            reportData.setNameStr("未查找到数据");
            reportData.setTelStr("未查找到数据");
            reportData.setAddressStr("未查找到数据");
            reportSheetData.add(reportData);
        }
        return reportSheetData;
    }
    private void loopSearch(String keywords, String location,
                            List<ReportData> reportSheetData, Set<String> firmSet) throws InterruptedException, IOException {
        int depth = 0;
        int MAX_DEPTH = 1;
        int page = currentPage;
        while (depth++ < MAX_DEPTH & depth <= 100) {
            currentPage = depth;
            System.out.println("正在搜索第" + depth + "页数据...");
            List<Firm> pageData = conditionalQueries(keywords, 20, location, "export");
            MAX_DEPTH = totalPages;
            if (pageData == null || pageData.isEmpty()){
                continue;
            }

            processFirms(pageData, firmSet, reportSheetData);

            Thread.sleep(300); // API 请求间隔
        }
        currentPage = page;
    }

    /*private void loopSearch(String keywords, String location, int startPage,
                            List<ReportData> reportSheetData, Set<String> firmSet) throws InterruptedException, IOException {
        int current = startPage;
        int depth = 0;
        int MAX_DEPTH = 5;
        int page = currentPage;
        while (depth++ < MAX_DEPTH) {
            boolean hasData = false;

            // 计算当前轮次要请求的页码范围：从 currentPage 开始取3页
            for (int i = current; i <= current + 2; i++) {
                System.out.println("正在搜索第" + currentPage + "页数据...");
                currentPage = i;
                List<Firm> pageData = conditionalQueries(keywords, 20, location, "export");
                MAX_DEPTH = (int) Math.ceil((double) totalPages / 3);
                if (pageData == null || pageData.isEmpty()){
                    continue;
                }

                processFirms(pageData, firmSet, reportSheetData);
                hasData = true;
            }

            if (!hasData){
                break;
            }

            Thread.sleep(3000); // API 请求间隔
            current += 3; // 下一轮开始页为当前轮最后一页+1
        }
        currentPage = page;
    }*/
    private void processFirms(List<Firm> pageData, Set<String> firmSet, List<ReportData> reportSheetData) {
        for (Firm firm : pageData) {
            processTelField(firm);
            processNameField(firm);
            processAddressField(firm);

            if (StringUtils.isEmpty(firm.getTelStr())){
                continue;
            }
            if (firmSet.contains(firm.getNameStr())){
                continue;
            }

            firmSet.add(firm.getNameStr());
            ReportData reportData = new ReportData();
            reportData.setNameStr(firm.getNameStr());
            reportData.setTelStr(firm.getTelStr());
            reportData.setAddressStr(firm.getAddressStr());
            reportSheetData.add(reportData);
        }
    }
    private void processTelField(Firm firm) {
        if (firm == null){
            return;
        }

        Object tel = firm.getTel();
        if (tel == null) {
            firm.setTelStr("");
            return;
        }

        if (tel instanceof List<?>) {
            @SuppressWarnings("unchecked")
            List<String> telList = (List<String>) tel;
            firm.setTelStr(String.join("，", telList));
        } else if (tel instanceof String) {
            String phone = (String) tel;
            firm.setTelStr(Arrays.stream(phone.split(";"))
                    .filter(s -> s.length() == 11)
                    .collect(Collectors.joining(",")));
        } else {
            firm.setTelStr("");
        }
    }
    private void processNameField(Firm firm){
        if (firm == null){
            return;
        }

        Object naem = firm.getName();
        if (naem == null) {
            firm.setNameStr("");
            return;
        }

        if (naem instanceof List<?>) {
            @SuppressWarnings("unchecked")
            List<String> nameList = (List<String>) naem;
            firm.setNameStr(String.join("，", nameList));
        } else if (naem instanceof String) {
            firm.setNameStr((String) naem);
        } else {
            firm.setNameStr("");
        }
    }
    private void processAddressField(Firm firm){
        if (firm == null){
            return;
        }

        Object address = firm.getAddress();
        if (address == null) {
            firm.setAddressStr("");
            return;
        }

        if (address instanceof List<?>) {
            @SuppressWarnings("unchecked")
            List<String> addressList = (List<String>) address;
            firm.setAddressStr(String.join("，", addressList));
        } else if (address instanceof String) {
            firm.setAddressStr((String) address);
        } else {
            firm.setAddress("");
        }
    }
    public static class Company {
        private final String index;
        private final String name;
        private final String address;
        private final String phone;
        private final String location;
        private final String type;
        private final String rating;

        public Company(String index, String name, String address, String phone, String location, String type, String rating) {
            this.index = index;
            this.name = name;
            this.address = address;
            this.phone = phone;
            this.location = location;
            this.type = type;
            this.rating = rating;
        }

        public String getIndex() { return index; }
        public String getName() { return name; }
        public String getAddress() { return address; }
        public String getPhone() { return phone; }
        public String getLocation() { return location; }
        public String getType() { return type; }
        public String getRating() { return rating; }
    }

}
